#ifndef FIX_HPP
#define FIX_HPP
#include <stdexcept>
#include <vector>
#include <stack>
#include "config.hpp"
namespace myh {
    namespace fix{
        class ExpressionEvaluator {
        protected:
            std::string expression;
            static bool is_operator(char c) {
                return c == '+' || c == '-' || c == '*' || c == '/' || c == '%';
            }
            enum class Precedence {
                LOW=1,
                HIGH=2
            };
            static Precedence get_precedence(char op) {
                switch(op) {
                    case '+':
                    case '-': return Precedence::LOW;
                    case '*':
                    case '/':
                    case '%': return Precedence::HIGH;
                    default: throw std::invalid_argument("Unknown operator");
                }
            }
        public:
            virtual ~ExpressionEvaluator() = default;
            virtual long long evaluate() const = 0;
            std::string get_expression() const { return expression; }
            long long operator()() const {
                return evaluate();
            }
        };
        class PostfixEvaluator : public ExpressionEvaluator {
        private:
            void process_operand(std::stack<long long>& operands, long long& current_num, bool& parsing_num) const {
                if (parsing_num) {
                    operands.push(current_num);
                    current_num = 0;
                    parsing_num = false;
                }
            }
            PostfixEvaluator(const std::string& expr) {
                expression = expr;
            }
        public:
            PostfixEvaluator(const PostfixEvaluator& other) {
                expression=other.expression;
            }
            long long evaluate() const override {
                std::stack<long long> operands;
                long long current_num = 0;
                bool parsing_num = false;
                for (char c : expression) {
                    if (isspace(c)) {
                        process_operand(operands, current_num, parsing_num);
                        continue;
                    }
                    if(isdigit(c)) {
                        current_num = current_num * 10 + (c - '0');
                        parsing_num = true;
                    }else if(is_operator(c)) {
                        process_operand(operands, current_num, parsing_num);
                        if (operands.size() < 2) {
                            throw std::runtime_error("Insufficient operands for operator '" + std::string(1, c) + "'");
                        }
                        long long b = operands.top(); operands.pop();
                        long long a = operands.top(); operands.pop();
                        switch (c) {
                            case '+': operands.push(a + b); break;
                            case '-': operands.push(a - b); break;
                            case '*': operands.push(a * b); break;
                            case '/': operands.push(a / b); break;
                            case '%': operands.push(a % b); break;
                        }
                    }else throw std::runtime_error("Invalid character in expression");
                }
                process_operand(operands, current_num, parsing_num);
                if(operands.size() != 1) throw std::runtime_error("Malformed postfix expression");
                return operands.top();
            }
            friend class InfixEvaluator;
        };
        class InfixEvaluator:public ExpressionEvaluator {
        private:
            static bool is_valid_expression(const std::string& expr) {
                int bracket_count=0;
                bool last_was_operator=true;
                for(char c : expr) {
                    if(isspace(c)) continue;
                    if(c == '(') {
                        if (!last_was_operator) return false;
                        bracket_count++;
                        last_was_operator = true;
                    }else if(c == ')') {
                        if(last_was_operator || bracket_count == 0) return false;
                        bracket_count--;
                        last_was_operator = false;
                    }else if(is_operator(c)) {
                        if (last_was_operator) return false;
                        last_was_operator = true;
                    }
                    else if(isdigit(c)) last_was_operator = false;
                    else return false;
                }
                return bracket_count == 0 && !last_was_operator;
            }

        public:
            InfixEvaluator() : ExpressionEvaluator() {}
            explicit InfixEvaluator(const std::string& expr) {
                if(!is_valid_expression(expr))
                    throw std::invalid_argument("Invalid infix expression");
                expression = expr;
            }
            PostfixEvaluator to_postfix() const {
                std::stack<char> operators;
                std::string postfix_expr;
                long long current_num = 0;
                bool parsing_num = false;
                auto process_operand = [&]() {
                    if (parsing_num) {
                        postfix_expr += std::to_string(current_num) + " ";
                        current_num = 0;
                        parsing_num = false;
                    }
                };
                for (char c : expression) {
                    if(isspace(c)) {
                        process_operand();
                        continue;
                    }
                    if(isdigit(c)) {
                        current_num = current_num * 10 + (c - '0');
                        parsing_num = true;
                    }else if(c == '(') {
                        process_operand();
                        operators.push(c);
                    }else if(c == ')') {
                        process_operand();
                        while(!operators.empty() && operators.top() != '(') {
                            postfix_expr += operators.top();
                            postfix_expr += ' ';
                            operators.pop();
                        }
                        if(operators.empty()) throw std::runtime_error("Mismatched parentheses");
                        operators.pop();
                    }else if(is_operator(c)) {
                        process_operand();
                        while(!operators.empty() && operators.top() != '(' && 
                            get_precedence(operators.top()) >= get_precedence(c)) {
                            postfix_expr += operators.top();
                            postfix_expr += ' ';
                            operators.pop();
                        }
                        operators.push(c);
                    }
                }
                process_operand();
                while(!operators.empty()) {
                    if(operators.top() == '(') throw std::runtime_error("Mismatched parentheses");
                    postfix_expr += operators.top();
                    postfix_expr += ' ';
                    operators.pop();
                }
                if(!postfix_expr.empty() && postfix_expr.back() == ' ')
                    postfix_expr.pop_back();
                return PostfixEvaluator(postfix_expr);
            }
            long long evaluate() const override {
                return to_postfix().evaluate();
            }
        };
    }
}
#endif
